package org.mozhu.mboot.admin.personal.message.service;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.mozhu.mboot.admin.personal.message.entiity.Message;
import org.mozhu.mboot.admin.personal.message.entiity.MessageState;
import org.mozhu.mboot.admin.personal.message.repository.MessageRepository;
import org.mozhu.mboot.admin.system.account.service.UserService;
import org.mozhu.mboot.core.data.BaseService;
import org.mozhu.mboot.core.data.SearchFilters;
import org.mozhu.mboot.core.data.Searchable;
import org.mozhu.mboot.core.data.filter.Operator;
import org.mozhu.mboot.core.data.filter.SearchFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 消息 - 业务层实现类
 *
 * @author mozhu
 */
@Transactional
@Service(value = "messageService")
public class MessageServiceImpl extends BaseService<Message, Long> implements MessageService {

    private MessageRepository getBaseRepository() {
        return (MessageRepository) baseRepository;
    }

    @Autowired
    UserService userService;

    /**
     * 改变发件人 消息的原状态为目标状态
     *
     * @param senderId
     * @param oldState
     * @param newState
     */
    public Integer changeSenderState(Long senderId, MessageState oldState, MessageState newState) {
        Date changeDate = new Date();
        return this.getBaseRepository().changeSenderState(senderId, oldState, newState, changeDate);
    }

    /**
     * 改变收件人人 消息的原状态为目标状态
     *
     * @param receiverId
     * @param oldState
     * @param newState
     */
    public Integer changeReceiverState(Long receiverId, MessageState oldState, MessageState newState) {
        Date changeDate = new Date();
        return this.getBaseRepository().changeReceiverState(receiverId, oldState, newState, changeDate);
    }

    /**
     * 物理删除那些已删除的（即收件人和发件人 同时都删除了的）
     *
     * @param deletedState
     */
    public Integer clearDeletedMessage(MessageState deletedState) {
        return this.getBaseRepository().clearDeletedMessage(deletedState);
    }

    /**
     * 更改状态
     *
     * @param oldStates
     * @param newState
     * @param expireDays 当前时间-过期天数 时间之前的消息将改变状态
     */
    public Integer changeState(ArrayList<MessageState> oldStates, MessageState newState, int expireDays) {
        Date changeDate = new Date();
        Integer count = this.getBaseRepository().changeSenderState(oldStates, newState, changeDate, DateUtils.addDays(changeDate, -expireDays));
        count += this.getBaseRepository().changeReceiverState(oldStates, newState, changeDate, DateUtils.addDays(changeDate, -expireDays));
        return count;
    }

    /**
     * 统计用户收件箱未读消息
     *
     * @param userId
     * @return
     */
    @Override
    public int countUnread(Long userId) {
        return this.getBaseRepository().countUnread(userId, MessageState.in_box);
    }

    @Override
    public void markRead(final Long userId, final Long[] ids) {
        if (ArrayUtils.isEmpty(ids)) {
            return;
        }
        this.getBaseRepository().markRead(userId, Arrays.asList(ids));
    }

    @Override
    public Page<Message> findUserMessage(Long userId, MessageState state, Searchable searchable) {
        switch (state) {
            // sender的
            case draft_box:
            case out_box:
                searchable.addSearchFilter(SearchFilters.and(SearchFilters.createFilter("senderId", Operator.EQ, userId), SearchFilters.createFilter("senderState", Operator.EQ, state)));
                break;
            // receiver的
            case in_box:
                searchable.addSearchFilter(SearchFilters.and(SearchFilters.createFilter("receiverId", Operator.EQ, userId), SearchFilters.createFilter("receiverState", Operator.EQ, state)));
                break;
            // sender or receiver的
            case store_box:
            case trash_box:
                // sender
                SearchFilter searchFilter1 = SearchFilters.and(SearchFilters.createFilter("senderId", Operator.EQ, userId), SearchFilters.createFilter("senderState", Operator.EQ, state));
                SearchFilter searchFilter2 = SearchFilters.and(SearchFilters.createFilter("receiverId", Operator.EQ, userId), SearchFilters.createFilter("receiverState", Operator.EQ, state));
                searchable.addSearchFilter(SearchFilters.or(searchFilter1, searchFilter2));
            case delete_box:
        }
        return this.getBaseRepository().findAll(searchable);
    }

    @Override
    public List<Message> findAncestorsAndDescendants(Message message) {
        List<SearchFilter> searchFilters = Lists.newArrayList();
        // 祖先 不为空 从祖先查起
        if (!StringUtils.isEmpty(message.getParentIds())) {
            String ancestorsId = message.getParentIds().split("/")[0];
            SearchFilter searchFilter = SearchFilters.or(SearchFilters.createFilter("parentIds", Operator.PLIKE, ancestorsId + "/"),
                    SearchFilters.createFilter("id", Operator.EQ, Long.valueOf(ancestorsId)));
            searchFilters.add(searchFilter);
        } else {
            // 祖先为空 查自己的后代
            String descendantsParentIds = message.makeSelfAsParentIds();
            searchFilters.add(SearchFilters.createFilter("parentIds", Operator.PLIKE, descendantsParentIds));
        }
        List<Message> result = this.getBaseRepository().findAll(searchFilters, SearchFilters.createSort(Direction.ASC, "id"));
        // 把自己排除
        result.remove(message);

        // 删除 不可见的消息 如垃圾箱/已删除
        for (int i = result.size() - 1; i >= 0; i--) {
            Message m = result.get(i);

            if (Objects.equals(m.getSenderId(), message.getSenderId()) && (m.getSenderState() == MessageState.trash_box || m.getSenderState() == MessageState.delete_box)) {
                result.remove(i);
            }

            if (Objects.equals(m.getReceiverId(), message.getSenderId()) && (m.getSenderState() == MessageState.trash_box || m.getSenderState() == MessageState.delete_box)) {
                result.remove(i);
            }
        }

        return result;
    }

    @Override
    public void saveDraft(Message message) {
        message.setSenderState(MessageState.draft_box);
        message.setReceiverState(null);
        this.getBaseRepository().save(message);
    }

    @Override
    public void send(Message message) {
        Date now = new Date();
        message.setSendDate(now);
        message.setSenderState(MessageState.out_box);
        message.setSenderStateChangeDate(now);
        message.setReceiverState(MessageState.in_box);
        message.setReceiverStateChangeDate(now);
        if (message.getParentId() != null) {
            Message parent = findById(message.getParentId());
            if (parent != null) {
                message.setParentIds(parent.makeSelfAsParentIds());
            }
        }

        this.getBaseRepository().save(message);

        // TODO 通知新消息已发送

    }

    @Override
    public void recycle(Long userId, Long messageId) {
        changeState(userId, messageId, MessageState.trash_box);
    }

    @Override
    public void recycle(Long userId, Long[] messageIds) {
        for (Long messageId : messageIds) {
            recycle(userId, messageId);
        }
    }

    @Override
    public void store(Long userId, Long messageId) {
        changeState(userId, messageId, MessageState.store_box);
    }

    @Override
    public void store(Long userId, Long[] messageIds) {
        for (Long messageId : messageIds) {
            store(userId, messageId);
        }
    }

    @Override
    public void delete(Long userId, Long messageId) {
        changeState(userId, messageId, MessageState.delete_box);
    }

    @Override
    public void delete(Long userId, Long[] messageIds) {
        for (Long messageId : messageIds) {
            delete(userId, messageId);
        }
    }

    /**
     * 变更状态 根据用户id是收件人/发件人 决定更改哪个状态
     *
     * @param userId
     * @param messageId
     * @param state
     */
    private void changeState(Long userId, Long messageId, MessageState state) {
        Message message = findById(messageId);
        if (message == null) {
            return;
        }
        if (userId.equals(message.getSenderId())) {
            changeSenderState(message, state);
        } else {
            changeReceiverState(message, state);
        }
        this.getBaseRepository().save(message);
    }

    @Override
    public void clearBox(Long userId, MessageState state) {
        switch (state) {
            case draft_box:
                clearBox(userId, MessageState.draft_box, MessageState.trash_box);
                break;
            case in_box:
                clearBox(userId, MessageState.in_box, MessageState.trash_box);
                break;
            case out_box:
                clearBox(userId, MessageState.out_box, MessageState.trash_box);
                break;
            case store_box:
                clearBox(userId, MessageState.store_box, MessageState.trash_box);
                break;
            case trash_box:
                clearBox(userId, MessageState.trash_box, MessageState.delete_box);
                break;
            default:
                // none;
                break;
        }
    }

    @Override
    public void clearDraftBox(Long userId) {
        clearBox(userId, MessageState.draft_box);
    }

    @Override
    public void clearInBox(Long userId) {
        clearBox(userId, MessageState.in_box);
    }

    @Override
    public void clearOutBox(Long userId) {
        clearBox(userId, MessageState.out_box);
    }

    @Override
    public void clearStoreBox(Long userId) {
        clearBox(userId, MessageState.store_box);
    }

    @Override
    public void clearTrashBox(Long userId) {
        clearBox(userId, MessageState.trash_box);
    }

    private void clearBox(Long userId, MessageState oldState, MessageState newState) {
        if (oldState == MessageState.draft_box || oldState == MessageState.out_box || oldState == MessageState.store_box || oldState == MessageState.trash_box) {

            changeSenderState(userId, oldState, newState);
        }
        if (oldState == MessageState.in_box || oldState == MessageState.store_box || oldState == MessageState.trash_box) {
            changeReceiverState(userId, oldState, newState);
        }
    }

    @Override
    public void markRead(Message message) {
        if (Boolean.TRUE.equals(message.getRead())) {
            return;
        }
        message.setRead(Boolean.TRUE);
        this.getBaseRepository().save(message);
    }

    @Override
    public void markReplied(Message message) {
        if (Boolean.TRUE.equals(message.getReplied())) {
            return;
        }
        message.setReplied(Boolean.TRUE);
        this.getBaseRepository().save(message);
    }

    private void changeSenderState(Message message, MessageState state) {
        message.setSenderState(state);
        message.setSenderStateChangeDate(new Date());
    }

    private void changeReceiverState(Message message, MessageState state) {
        message.setReceiverState(state);
        message.setReceiverStateChangeDate(new Date());
    }

}
